/*================================================================
*   Copyright (C) 2019 SangforLtd. All rights reserved.
*   
*   文件名称：test.cpp
*   创 建 者：Ann34857
*   创建日期：2019年07月30日
*   描    述：
*
================================================================*/


#include <iostream>
#include <queue>
#include <pthread.h>
#include <unistd.h>
using namespace std;

class CircularQueue
{
  public:
    CircularQueue(int size = 100)
      :m_Size(size)
    {
      //初始化互斥锁,使用默认的锁类型 即：PTHREAD_MUTEX_TIMED_NP ，其余的请求锁的线程会形成一个等待队列
      pthread_mutex_init(&m_Mutex,NULL);
      //初始化条件变量
      pthread_cond_init(&m_CondComsumer,NULL);
      pthread_cond_init(&m_CondProductor,NULL);
    }

    ~CircularQueue()
    {
      //释放互斥锁
      pthread_mutex_destroy(&m_Mutex);
      //释放条件变量
      pthread_cond_destroy(&m_CondComsumer);
      pthread_cond_destroy(&m_CondProductor);
    }

    int Pop()
    {
      //加锁
      pthread_mutex_lock(&m_Mutex);
      //需要判断是否队列中有没有值
      while(IsEmpty())
      {
        printf("this CircularQueue is Empty!\n");
        pthread_cond_wait(&m_CondComsumer,&m_Mutex);
      }
      int ret = m_Que.front();
      m_Que.pop();
      pthread_mutex_unlock(&m_Mutex);
      //通知生产者
      pthread_cond_signal(&m_CondProductor);
      return ret;
    }

    void push(int data)
    {
      //防止多线程同时入队列，加互斥锁
      pthread_mutex_lock(&m_Mutex);
      //在准备入对队列之前需要判断是否环形队列已经放满了
      //while 其实很精髓，有多个线程同时在cond_wait的时候，当前这个线程没有竞争到资源，还是在循环
      while(IsFull())
      {
        //等待条件成熟
        printf("this CircularQueue is full\n");
        pthread_cond_wait(&m_CondProductor, &m_Mutex);
      }
      m_Que.push(data);
      pthread_mutex_unlock(&m_Mutex);
      //通知消费者
      pthread_cond_signal(&m_CondComsumer);
    }
  private:
    bool IsFull()
    {
      if(m_Que.size() >= m_Size)
      {
        return true;
      }
      return false;
    }

    bool IsEmpty()
    {
      if(m_Que.size() == 0)
      {
        return true;
      }
      return false;
    }
  private:
    //规定队列大小，模拟实现环形队列
    size_t m_Size;
    //队列
    queue<int> m_Que;
  private:
    //队列保护锁
    pthread_mutex_t m_Mutex;
    //生产者条件变量
    pthread_cond_t m_CondProductor;
    //消费者条件变量
    pthread_cond_t m_CondComsumer;
};


void* ProductFunc(void* arg)
{
  //生产者线程执行体
  int count = 1;
  CircularQueue* lpcir = (CircularQueue*)arg;
  while(1)
  {
    lpcir->push(count);
    printf("ProductFunc 生产count为[%d]\n",count);
    count++;
    sleep(1);
  }
}


void* ComsumerFunc(void* arg)
{
  int ret = -1;
  CircularQueue* lpcir = (CircularQueue*)arg;
  while(1)
  {
    ret = lpcir->Pop();
    printf("m_CondComsumer 消费count为[%d]\n",ret);
    sleep(1);
  }
}

int main()
{
  //创建环形队列
  CircularQueue* lpCir = new CircularQueue(100);

  //创建线程
  int Count = 4;
  int ret = -1;
  pthread_t ProductTid[Count], ComsumerTid[Count];
  for(int i = 0; i < Count; i++)
  {
    ret = pthread_create(&ProductTid[i], NULL, ProductFunc, lpCir);
    if(ret != 0)
    {
      printf("%d pthread_create failed\n", i);
    }
    ret = pthread_create(&ComsumerTid[i],NULL,ComsumerFunc, lpCir);
    if(ret != 0)
    {
      printf("%d pthread_create failed\n", i);
    } 
  }

  //等待线程退出
  for(int i = 0; i < Count; i++)
  {
    pthread_join(ProductTid[i], NULL);
    pthread_join(ComsumerTid[i], NULL);
  }
  delete lpCir;
  return 0;
}
